/**
 * 预约日历组件
 *
 * 功能特性：
 * - 交互式日历选择
 * - 实时显示球台可用情况
 * - 时间段选择和拖拽
 * - 冲突检测和提示
 * - 响应式设计
 */

class ReservationCalendar {
    constructor(container, options = {}) {
        this.container = typeof container === 'string' ? document.querySelector(container) : container;
        this.options = {
            // 默认配置
            language: 'zh',
            startHour: 8,
            endHour: 22,
            slotDuration: 30, // 时间槽长度（分钟）
            minDuration: 60, // 最小预约时长（分钟）
            maxDuration: 240, // 最大预约时长（分钟）
            workDays: [1, 2, 3, 4, 5, 6, 7], // 工作日（1=周一）
            tables: [], // 球台列表
            reservations: [], // 已有预约
            coaches: [], // 教练列表
            onDateSelect: null,
            onTimeSelect: null,
            onReservationCreate: null,
            onReservationUpdate: null,
            onReservationDelete: null,
            ...options
        };

        this.currentDate = new Date();
        this.selectedDate = null;
        this.selectedTimeSlot = null;
        this.dragState = {
            isDragging: false,
            startSlot: null,
            endSlot: null,
            tableId: null
        };

        this.init();
    }

    init() {
        this.render();
        this.bindEvents();
        this.loadReservations();
    }

    render() {
        const html = `
            <div class="reservation-calendar">
                <div class="calendar-header">
                    <div class="calendar-nav">
                        <button type="button" class="btn-nav btn-prev" data-action="prev">
                            <i class="fas fa-chevron-left"></i>
                        </button>
                        <h3 class="calendar-title">${this.formatMonth(this.currentDate)}</h3>
                        <button type="button" class="btn-nav btn-next" data-action="next">
                            <i class="fas fa-chevron-right"></i>
                        </button>
                    </div>
                    <div class="calendar-actions">
                        <button type="button" class="btn btn-sm btn-outline-primary" data-action="today">
                            今天
                        </button>
                        <div class="view-toggle">
                            <button type="button" class="btn btn-sm btn-outline-secondary active" data-view="month">
                                月视图
                            </button>
                            <button type="button" class="btn btn-sm btn-outline-secondary" data-view="week">
                                周视图
                            </button>
                        </div>
                    </div>
                </div>

                <div class="calendar-body">
                    <div class="calendar-view calendar-month-view">
                        ${this.renderMonthView()}
                    </div>
                    <div class="calendar-view calendar-week-view" style="display: none;">
                        ${this.renderWeekView()}
                    </div>
                </div>

                <div class="schedule-panel">
                    <div class="schedule-header">
                        <h4>时间安排</h4>
                        <span class="schedule-date">${this.formatDate(this.selectedDate || this.currentDate)}</span>
                    </div>
                    <div class="schedule-body">
                        ${this.renderScheduleGrid()}
                    </div>
                </div>

                <div class="calendar-legend">
                    <div class="legend-item">
                        <span class="legend-color available"></span>
                        <span class="legend-text">可预约</span>
                    </div>
                    <div class="legend-item">
                        <span class="legend-color occupied"></span>
                        <span class="legend-text">已占用</span>
                    </div>
                    <div class="legend-item">
                        <span class="legend-color selected"></span>
                        <span class="legend-text">已选择</span>
                    </div>
                    <div class="legend-item">
                        <span class="legend-color conflict"></span>
                        <span class="legend-text">时间冲突</span>
                    </div>
                </div>
            </div>
        `;

        this.container.innerHTML = html;
        this.cacheElements();
    }

    cacheElements() {
        this.elements = {
            header: this.container.querySelector('.calendar-header'),
            title: this.container.querySelector('.calendar-title'),
            monthView: this.container.querySelector('.calendar-month-view'),
            weekView: this.container.querySelector('.calendar-week-view'),
            schedulePanel: this.container.querySelector('.schedule-panel'),
            scheduleBody: this.container.querySelector('.schedule-body'),
            scheduleDate: this.container.querySelector('.schedule-date')
        };
    }

    bindEvents() {
        // 导航事件
        this.container.addEventListener('click', (e) => {
            const action = e.target.getAttribute('data-action') || e.target.closest('[data-action]')?.getAttribute('data-action');

            switch (action) {
                case 'prev':
                    this.navigate(-1);
                    break;
                case 'next':
                    this.navigate(1);
                    break;
                case 'today':
                    this.goToToday();
                    break;
            }

            // 视图切换
            const view = e.target.getAttribute('data-view');
            if (view) {
                this.switchView(view);
            }

            // 日期选择
            if (e.target.classList.contains('calendar-day')) {
                this.selectDate(e.target);
            }

            // 时间槽选择
            if (e.target.classList.contains('time-slot')) {
                this.selectTimeSlot(e.target);
            }
        });

        // 拖拽事件
        this.container.addEventListener('mousedown', (e) => {
            if (e.target.classList.contains('time-slot') && !e.target.classList.contains('occupied')) {
                this.startDrag(e);
            }
        });

        this.container.addEventListener('mousemove', (e) => {
            if (this.dragState.isDragging) {
                this.updateDrag(e);
            }
        });

        this.container.addEventListener('mouseup', (e) => {
            if (this.dragState.isDragging) {
                this.endDrag(e);
            }
        });

        // 防止文本选择
        this.container.addEventListener('selectstart', (e) => {
            if (this.dragState.isDragging) {
                e.preventDefault();
            }
        });

        // 键盘事件
        document.addEventListener('keydown', (e) => {
            if (this.container.contains(document.activeElement)) {
                this.handleKeyboard(e);
            }
        });

        // 窗口调整大小
        window.addEventListener('resize', () => {
            this.handleResize();
        });
    }

    renderMonthView() {
        const year = this.currentDate.getFullYear();
        const month = this.currentDate.getMonth();
        const firstDay = new Date(year, month, 1);
        const lastDay = new Date(year, month + 1, 0);
        const startDate = new Date(firstDay);
        startDate.setDate(startDate.getDate() - (firstDay.getDay() || 7) + 1);

        let html = '<div class="calendar-grid">';

        // 星期标题
        html += '<div class="calendar-weekdays">';
        const weekdays = ['一', '二', '三', '四', '五', '六', '日'];
        weekdays.forEach(day => {
            html += `<div class="weekday">${day}</div>`;
        });
        html += '</div>';

        // 日期网格
        html += '<div class="calendar-days">';
        const currentMonth = month;
        let currentWeekDate = new Date(startDate);

        for (let week = 0; week < 6; week++) {
            for (let day = 0; day < 7; day++) {
                const date = new Date(currentWeekDate);
                const isCurrentMonth = date.getMonth() === currentMonth;
                const isToday = this.isToday(date);
                const isSelected = this.isSelected(date);
                const isWorkDay = this.options.workDays.includes(date.getDay() || 7);
                const hasReservations = this.hasReservationsOnDate(date);

                let classes = ['calendar-day'];
                if (!isCurrentMonth) classes.push('other-month');
                if (isToday) classes.push('today');
                if (isSelected) classes.push('selected');
                if (!isWorkDay) classes.push('non-work-day');
                if (hasReservations) classes.push('has-reservations');

                html += `
                    <div class="${classes.join(' ')}" data-date="${this.formatDateForData(date)}">
                        <span class="day-number">${date.getDate()}</span>
                        ${hasReservations ? '<span class="reservation-indicator"></span>' : ''}
                        ${this.renderDayMiniSchedule(date)}
                    </div>
                `;

                currentWeekDate.setDate(currentWeekDate.getDate() + 1);
            }
        }
        html += '</div></div>';

        return html;
    }

    renderWeekView() {
        const startOfWeek = this.getStartOfWeek(this.currentDate);
        let html = '<div class="week-grid">';

        // 时间轴
        html += '<div class="time-axis">';
        for (let hour = this.options.startHour; hour <= this.options.endHour; hour++) {
            html += `<div class="time-label">${hour.toString().padStart(2, '0')}:00</div>`;
        }
        html += '</div>';

        // 每天的列
        for (let day = 0; day < 7; day++) {
            const date = new Date(startOfWeek);
            date.setDate(date.getDate() + day);

            const isToday = this.isToday(date);
            const isWorkDay = this.options.workDays.includes(date.getDay() || 7);

            html += `
                <div class="day-column ${isToday ? 'today' : ''} ${!isWorkDay ? 'non-work-day' : ''}"
                     data-date="${this.formatDateForData(date)}">
                    <div class="day-header">
                        <div class="day-name">${this.getDayName(date)}</div>
                        <div class="day-date">${date.getDate()}</div>
                    </div>
                    <div class="day-schedule">
                        ${this.renderDaySchedule(date)}
                    </div>
                </div>
            `;
        }

        html += '</div>';
        return html;
    }

    renderScheduleGrid() {
        if (!this.selectedDate) {
            return '<div class="schedule-placeholder">请选择日期查看时间安排</div>';
        }

        const date = this.selectedDate;
        let html = '<div class="schedule-grid">';

        // 球台列表
        if (this.options.tables.length === 0) {
            html += '<div class="no-tables">暂无可用球台</div>';
        } else {
            // 表头
            html += '<div class="schedule-header-row">';
            html += '<div class="time-header">时间</div>';
            this.options.tables.forEach(table => {
                html += `<div class="table-header" data-table-id="${table.id}">${table.name}</div>`;
            });
            html += '</div>';

            // 时间槽
            for (let hour = this.options.startHour; hour < this.options.endHour; hour++) {
                for (let minute = 0; minute < 60; minute += this.options.slotDuration) {
                    const timeSlot = `${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}`;

                    html += '<div class="schedule-row">';
                    html += `<div class="time-cell">${timeSlot}</div>`;

                    this.options.tables.forEach(table => {
                        const slotDateTime = new Date(date);
                        slotDateTime.setHours(hour, minute, 0, 0);

                        const isOccupied = this.isSlotOccupied(table.id, slotDateTime);
                        const isSelected = this.isSlotSelected(table.id, slotDateTime);
                        const isConflict = this.isSlotConflict(table.id, slotDateTime);

                        let classes = ['time-slot'];
                        if (isOccupied) classes.push('occupied');
                        if (isSelected) classes.push('selected');
                        if (isConflict) classes.push('conflict');

                        html += `
                            <div class="${classes.join(' ')}"
                                 data-table-id="${table.id}"
                                 data-time="${timeSlot}"
                                 data-datetime="${slotDateTime.toISOString()}"
                                 title="${this.getSlotTooltip(table.id, slotDateTime)}">
                                ${isOccupied ? this.getReservationInfo(table.id, slotDateTime) : ''}
                            </div>
                        `;
                    });

                    html += '</div>';
                }
            }
        }

        html += '</div>';
        return html;
    }

    renderDayMiniSchedule(date) {
        const reservations = this.getReservationsForDate(date);
        if (reservations.length === 0) return '';

        let html = '<div class="mini-schedule">';
        reservations.slice(0, 2).forEach(reservation => {
            html += `<div class="mini-reservation" style="background-color: ${this.getStatusColor(reservation.status)}"></div>`;
        });
        if (reservations.length > 2) {
            html += `<div class="mini-more">+${reservations.length - 2}</div>`;
        }
        html += '</div>';

        return html;
    }

    renderDaySchedule(date) {
        const reservations = this.getReservationsForDate(date);
        let html = '';

        reservations.forEach(reservation => {
            const startHour = reservation.start_time.getHours();
            const startMinute = reservation.start_time.getMinutes();
            const duration = (reservation.end_time - reservation.start_time) / (1000 * 60); // 分钟

            const top = ((startHour - this.options.startHour) * 60 + startMinute) * 2; // 每分钟2px
            const height = duration * 2;

            html += `
                <div class="schedule-event"
                     style="top: ${top}px; height: ${height}px; background-color: ${this.getStatusColor(reservation.status)}"
                     data-reservation-id="${reservation.id}">
                    <div class="event-title">${reservation.student_name}</div>
                    <div class="event-time">${this.formatTime(reservation.start_time)}-${this.formatTime(reservation.end_time)}</div>
                </div>
            `;
        });

        return html;
    }

    // 导航方法
    navigate(direction) {
        const currentView = this.getCurrentView();
        if (currentView === 'month') {
            this.currentDate.setMonth(this.currentDate.getMonth() + direction);
        } else {
            this.currentDate.setDate(this.currentDate.getDate() + (direction * 7));
        }
        this.updateView();
    }

    goToToday() {
        this.currentDate = new Date();
        this.updateView();
    }

    switchView(view) {
        this.container.querySelectorAll('[data-view]').forEach(btn => {
            btn.classList.remove('active');
        });
        this.container.querySelector(`[data-view="${view}"]`).classList.add('active');

        this.container.querySelectorAll('.calendar-view').forEach(el => {
            el.style.display = 'none';
        });
        this.container.querySelector(`.calendar-${view}-view`).style.display = 'block';
    }

    selectDate(dayElement) {
        const dateStr = dayElement.getAttribute('data-date');
        this.selectedDate = new Date(dateStr);

        // 更新选中状态
        this.container.querySelectorAll('.calendar-day.selected').forEach(el => {
            el.classList.remove('selected');
        });
        dayElement.classList.add('selected');

        // 更新时间表
        this.updateSchedulePanel();

        // 触发回调
        if (this.options.onDateSelect) {
            this.options.onDateSelect(this.selectedDate);
        }
    }

    selectTimeSlot(slotElement) {
        if (slotElement.classList.contains('occupied')) return;

        const tableId = parseInt(slotElement.getAttribute('data-table-id'));
        const datetime = new Date(slotElement.getAttribute('data-datetime'));

        this.selectedTimeSlot = {
            tableId,
            datetime,
            element: slotElement
        };

        // 更新选中状态
        this.container.querySelectorAll('.time-slot.selected').forEach(el => {
            el.classList.remove('selected');
        });
        slotElement.classList.add('selected');

        // 触发回调
        if (this.options.onTimeSelect) {
            this.options.onTimeSelect(this.selectedTimeSlot);
        }
    }

    // 拖拽方法
    startDrag(e) {
        const slot = e.target;
        if (!slot.classList.contains('time-slot') || slot.classList.contains('occupied')) return;

        this.dragState.isDragging = true;
        this.dragState.startSlot = slot;
        this.dragState.tableId = parseInt(slot.getAttribute('data-table-id'));

        slot.classList.add('drag-start');
        this.container.style.userSelect = 'none';

        e.preventDefault();
    }

    updateDrag(e) {
        if (!this.dragState.isDragging) return;

        const slot = document.elementFromPoint(e.clientX, e.clientY);
        if (!slot || !slot.classList.contains('time-slot')) return;

        const tableId = parseInt(slot.getAttribute('data-table-id'));
        if (tableId !== this.dragState.tableId) return;

        // 清除之前的拖拽选择
        this.container.querySelectorAll('.drag-selecting').forEach(el => {
            el.classList.remove('drag-selecting');
        });

        // 选择范围内的时间槽
        const startIndex = this.getSlotIndex(this.dragState.startSlot);
        const currentIndex = this.getSlotIndex(slot);
        const minIndex = Math.min(startIndex, currentIndex);
        const maxIndex = Math.max(startIndex, currentIndex);

        const slots = this.getTableSlots(tableId);
        for (let i = minIndex; i <= maxIndex; i++) {
            if (slots[i] && !slots[i].classList.contains('occupied')) {
                slots[i].classList.add('drag-selecting');
            }
        }

        this.dragState.endSlot = slot;
    }

    endDrag(e) {
        if (!this.dragState.isDragging) return;

        const selectedSlots = this.container.querySelectorAll('.drag-selecting');
        if (selectedSlots.length > 0) {
            this.createTimeSelection(selectedSlots);
        }

        // 清理拖拽状态
        this.container.querySelectorAll('.drag-start, .drag-selecting').forEach(el => {
            el.classList.remove('drag-start', 'drag-selecting');
        });

        this.dragState = {
            isDragging: false,
            startSlot: null,
            endSlot: null,
            tableId: null
        };

        this.container.style.userSelect = '';
    }

    createTimeSelection(slots) {
        const startSlot = slots[0];
        const endSlot = slots[slots.length - 1];

        const startTime = new Date(startSlot.getAttribute('data-datetime'));
        const endTime = new Date(endSlot.getAttribute('data-datetime'));
        endTime.setMinutes(endTime.getMinutes() + this.options.slotDuration);

        const duration = (endTime - startTime) / (1000 * 60);

        // 验证时长
        if (duration < this.options.minDuration) {
            this.showMessage(`最少需要预约${this.options.minDuration}分钟`, 'warning');
            return;
        }

        if (duration > this.options.maxDuration) {
            this.showMessage(`最多只能预约${this.options.maxDuration}分钟`, 'warning');
            return;
        }

        const selection = {
            tableId: this.dragState.tableId,
            startTime,
            endTime,
            duration,
            slots: Array.from(slots)
        };

        // 检查冲突
        if (this.checkTimeConflict(selection)) {
            this.showMessage('选择的时间段存在冲突', 'error');
            return;
        }

        this.selectedTimeSlot = selection;

        // 更新显示
        this.updateTimeSelection(selection);

        // 触发回调
        if (this.options.onTimeSelect) {
            this.options.onTimeSelect(selection);
        }
    }

    // 工具方法
    updateView() {
        this.elements.title.textContent = this.formatMonth(this.currentDate);

        const currentView = this.getCurrentView();
        if (currentView === 'month') {
            this.elements.monthView.innerHTML = this.renderMonthView();
        } else {
            this.elements.weekView.innerHTML = this.renderWeekView();
        }

        this.updateSchedulePanel();
    }

    updateSchedulePanel() {
        if (this.selectedDate) {
            this.elements.scheduleDate.textContent = this.formatDate(this.selectedDate);
            this.elements.scheduleBody.innerHTML = this.renderScheduleGrid();
        }
    }

    getCurrentView() {
        const activeButton = this.container.querySelector('[data-view].active');
        return activeButton ? activeButton.getAttribute('data-view') : 'month';
    }

    loadReservations() {
        // 这里应该从服务器加载预约数据
        // 为了演示，使用示例数据
        this.options.reservations = this.generateSampleReservations();
        this.updateView();
    }

    generateSampleReservations() {
        const reservations = [];
        const today = new Date();

        for (let i = 0; i < 10; i++) {
            const date = new Date(today);
            date.setDate(date.getDate() + Math.floor(Math.random() * 14) - 7);

            const startHour = this.options.startHour + Math.floor(Math.random() * (this.options.endHour - this.options.startHour - 2));
            const startTime = new Date(date);
            startTime.setHours(startHour, 0, 0, 0);

            const endTime = new Date(startTime);
            endTime.setHours(startHour + 1 + Math.floor(Math.random() * 2));

            reservations.push({
                id: i + 1,
                table_id: (i % this.options.tables.length) + 1,
                start_time: startTime,
                end_time: endTime,
                student_name: `学员${i + 1}`,
                coach_name: `教练${(i % 3) + 1}`,
                status: ['pending', 'confirmed', 'completed'][Math.floor(Math.random() * 3)]
            });
        }

        return reservations;
    }

    // 工具函数
    formatMonth(date) {
        return `${date.getFullYear()}年${(date.getMonth() + 1).toString().padStart(2, '0')}月`;
    }

    formatDate(date) {
        const days = ['日', '一', '二', '三', '四', '五', '六'];
        return `${date.getFullYear()}年${(date.getMonth() + 1).toString().padStart(2, '0')}月${date.getDate().toString().padStart(2, '0')}日 星期${days[date.getDay()]}`;
    }

    formatDateForData(date) {
        return date.toISOString().split('T')[0];
    }

    formatTime(date) {
        return `${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`;
    }

    getDayName(date) {
        const days = ['日', '一', '二', '三', '四', '五', '六'];
        return days[date.getDay()];
    }

    getStartOfWeek(date) {
        const start = new Date(date);
        const day = start.getDay();
        const diff = start.getDate() - day + (day === 0 ? -6 : 1);
        start.setDate(diff);
        start.setHours(0, 0, 0, 0);
        return start;
    }

    isToday(date) {
        const today = new Date();
        return date.toDateString() === today.toDateString();
    }

    isSelected(date) {
        return this.selectedDate && date.toDateString() === this.selectedDate.toDateString();
    }

    hasReservationsOnDate(date) {
        return this.getReservationsForDate(date).length > 0;
    }

    getReservationsForDate(date) {
        return this.options.reservations.filter(reservation => {
            const reservationDate = new Date(reservation.start_time);
            return reservationDate.toDateString() === date.toDateString();
        });
    }

    isSlotOccupied(tableId, datetime) {
        return this.options.reservations.some(reservation => {
            return reservation.table_id === tableId &&
                   datetime >= new Date(reservation.start_time) &&
                   datetime < new Date(reservation.end_time);
        });
    }

    isSlotSelected(tableId, datetime) {
        if (!this.selectedTimeSlot) return false;

        if (Array.isArray(this.selectedTimeSlot.slots)) {
            return this.selectedTimeSlot.slots.some(slot =>
                slot.getAttribute('data-datetime') === datetime.toISOString()
            );
        }

        return this.selectedTimeSlot.tableId === tableId &&
               this.selectedTimeSlot.datetime.getTime() === datetime.getTime();
    }

    isSlotConflict(tableId, datetime) {
        // 检查是否与其他预约冲突
        return false; // 简化实现
    }

    getSlotTooltip(tableId, datetime) {
        const table = this.options.tables.find(t => t.id === tableId);
        const tableName = table ? table.name : `球台${tableId}`;
        const timeStr = this.formatTime(datetime);

        if (this.isSlotOccupied(tableId, datetime)) {
            const reservation = this.getReservationAt(tableId, datetime);
            return `${tableName} ${timeStr} - ${reservation.student_name}的课程`;
        }

        return `${tableName} ${timeStr} - 可预约`;
    }

    getReservationInfo(tableId, datetime) {
        const reservation = this.getReservationAt(tableId, datetime);
        if (!reservation) return '';

        return `<div class="reservation-info">${reservation.student_name}</div>`;
    }

    getReservationAt(tableId, datetime) {
        return this.options.reservations.find(reservation => {
            return reservation.table_id === tableId &&
                   datetime >= new Date(reservation.start_time) &&
                   datetime < new Date(reservation.end_time);
        });
    }

    getStatusColor(status) {
        const colors = {
            pending: '#ffc107',
            confirmed: '#17a2b8',
            completed: '#28a745',
            cancelled: '#dc3545'
        };
        return colors[status] || '#6c757d';
    }

    getSlotIndex(slot) {
        const slots = this.getTableSlots(parseInt(slot.getAttribute('data-table-id')));
        return Array.from(slots).indexOf(slot);
    }

    getTableSlots(tableId) {
        return this.container.querySelectorAll(`[data-table-id="${tableId}"].time-slot`);
    }

    checkTimeConflict(selection) {
        // 检查时间冲突
        return false; // 简化实现
    }

    updateTimeSelection(selection) {
        // 清除之前的选择
        this.container.querySelectorAll('.time-slot.selected').forEach(el => {
            el.classList.remove('selected');
        });

        // 添加新的选择
        selection.slots.forEach(slot => {
            slot.classList.add('selected');
        });
    }

    showMessage(message, type = 'info') {
        // 显示消息提示
        console.log(`[${type.toUpperCase()}] ${message}`);

        // 可以集成 toastr 或其他消息库
        if (window.showAlert) {
            window.showAlert(type, message);
        }
    }

    handleKeyboard(e) {
        switch (e.key) {
            case 'ArrowLeft':
                this.navigate(-1);
                e.preventDefault();
                break;
            case 'ArrowRight':
                this.navigate(1);
                e.preventDefault();
                break;
            case 'Home':
                this.goToToday();
                e.preventDefault();
                break;
        }
    }

    handleResize() {
        // 响应式处理
        const width = this.container.offsetWidth;
        if (width < 768) {
            this.switchView('week');
        }
    }

    // 公共API
    getSelectedDate() {
        return this.selectedDate;
    }

    getSelectedTimeSlot() {
        return this.selectedTimeSlot;
    }

    setDate(date) {
        this.currentDate = new Date(date);
        this.updateView();
    }

    setTables(tables) {
        this.options.tables = tables;
        this.updateSchedulePanel();
    }

    setReservations(reservations) {
        this.options.reservations = reservations;
        this.updateView();
    }

    refresh() {
        this.loadReservations();
    }

    destroy() {
        // 清理事件监听器
        this.container.innerHTML = '';
    }
}

// 导出为全局变量
window.ReservationCalendar = ReservationCalendar;